//This file reads from lightwave .obj scenes
#include "stdafx.h"
#include "lwobject.h"
#include "phong_shaders.h"
#include "proceduralShader.h"

#ifdef __unix
#include <libgen.h>
#define _strnicmp strncasecmp
#endif

#ifdef _WIN32
#define _PATH_SEPARATOR '\\'
#endif
#ifdef __unix
#define _PATH_SEPARATOR '/'
#endif

namespace objLoaderUtil
{
	typedef std::map<std::string, size_t> t_materialMap;

	void skipWS(const char * &aStr)
	{
		while(isspace(*aStr))
			aStr++;
	}

	std::string endSpaceTrimmed(const char* _str)
	{
		size_t len = strlen(_str);
		const char *firstChar = _str;
		const char *lastChar = firstChar + len - 1;
		while(lastChar >= firstChar && isspace(*lastChar))
			lastChar--;

		return std::string(firstChar, lastChar + 1);
	}


	std::string getDirName(const std::string& _name)
	{
		std::string objDir;
#if _MSC_VER >= 1400
		char fileDir[4096];
		_splitpath_s(_name.c_str(), NULL, 0, fileDir, sizeof(fileDir), NULL, 0, NULL, 0);
		objDir = fileDir;
#endif

#ifdef __unix
		char *fnCopy = strdup(_name.c_str());
		const char* dirName = dirname(fnCopy);
		objDir = dirName;
		free(fnCopy);
		//std::cerr << "Dirname:" << objDir << std::endl;

#endif // __unix

		return objDir;
	}


	
struct Punkt{
	Point point;
	size_t vert, norm, tex;
};



//split a Face at the longest side. One is stored in itself and the other is stored in the predeclared f2
//if splitting is skipped, because the longest edge is too short, return false, otherwise true
bool split(LWObject::Face* f1,LWObject::Face* f2){
	//minimum size of the longest side to skip
	float cancel = 0.5f;
	//the three vertexpoints of f1
	Point vert1 = f1->getLW()->vertices[f1->vert1],
		vert2 = f1->getLW()->vertices[f1->vert2],
		vert3 = f1->getLW()->vertices[f1->vert3];
	//the vectors along the three edges of f1
	Vector v1_2 = vert2-vert1,
		v2_3 = vert3-vert2,
		v3_1 = vert1-vert3;
	//the length of the three edge-vectors
	float l1_2 = v1_2.len(),
		l2_3 = v2_3.len(),
		l3_1 = v3_1.len();
	//the index of the longest edge
	int l_max = (l1_2 > l2_3) ? ((l1_2 > l3_1) ? 0 : 2) : ((l2_3 > l3_1) ? 1 : 2);
	//three structs to handle all three split-possibilities in an easy way
	//std::cout<<l_max<<" 0: "<<l1_2<<" 1: "<<l2_3<<" 2: "<<l3_1<<std::endl;
	Punkt p1, p2, p3;
	if(l_max==0){
		//std::cout<<"l1_2 "<<l1_2<<std::endl;
		//if the longest edge is too short, skip splitting
		if(l1_2 < cancel) return false;
		//save the values of the three vertex-points in the structs
		p1.point = vert1;	p1.vert = f1->vert1;	p1.norm = f1->norm1;	p1.tex = f1->tex1;
		p2.point = vert2;	p2.vert = f1->vert2;	p2.norm = f1->norm2;	p2.tex = f1->tex2;
		p3.point = vert3;	p3.vert = f1->vert3;	p3.norm = f1->norm3;	p3.tex = f1->tex3;
	}
	else
		if(l_max==1){
			//std::cout<<"l2_3 "<<l2_3<<std::endl;
			//if the longest edge is too short, skip splitting
			if(l2_3 < cancel) return false;
			//save the values of the three vertex-points in the structs
			p1.point = vert2;	p1.vert = f1->vert2;	p1.norm = f1->norm2;	p1.tex = f1->tex2;
			p2.point = vert3;	p2.vert = f1->vert3;	p2.norm = f1->norm3;	p2.tex = f1->tex3;
			p3.point = vert1;	p3.vert = f1->vert1;	p3.norm = f1->norm1;	p3.tex = f1->tex1;
		}
		else
			if(l_max==2){
				//std::cout<<"l3_1 "<<l3_1<<std::endl;
				//if the longest edge is too short, skip splitting
				if(l3_1 < cancel) return false;
				//save the values of the three vertex-points in the structs
				p1.point = vert3;	p1.vert = f1->vert3;	p1.norm = f1->norm3;	p1.tex = f1->tex3;
				p2.point = vert1;	p2.vert = f1->vert1;	p2.norm = f1->norm1;	p2.tex = f1->tex1;
				p3.point = vert2;	p3.vert = f1->vert2;	p3.norm = f1->norm2;	p3.tex = f1->tex2;
			}
	
			//std::cout<<"p1: "<<p1.vert<<" p2: "<<p2.vert<<" p3: "<<p3.vert<<std::endl;

	//the new point between p1 and p2, its new normal and its new textureCoord as far as the old face had a texCoord
	Point cut = p1.point + (p2.point-p1.point)/2.f;
	Vector norm = ~((f1->getLW()->normals[p1.norm]+f1->getLW()->normals[p2.norm])/2.f);//calcNorm2(p1.point, p2.point, cut, f1->getLW()->normals[p1.norm], f1->getLW()->normals[p2.norm]);
	float2 tex;
	if(p1.tex!=-1 && p2.tex!=-1)
		tex = (f1->getLW()->texCoords[p1.tex]+f1->getLW()->texCoords[p2.tex])/2.f ;//calcTexCoord2(p1.point, p2.point, cut, f1->getLW()->texCoords[p1.tex], f1->getLW()->texCoords[p2.tex]);
	//the indices of the new point, normal and texCoord
	size_t index_cut = f1->getLW()->vertices.size(),
		index_norm = f1->getLW()->normals.size(),
		index_tex = (p1.tex!=-1 && p2.tex!=-1) ? f1->getLW()->texCoords.size() : -1;
	//save the new point, normal and texCoord
	f1->getLW()->vertices.push_back(cut);
	f1->getLW()->shifted.push_back(0);
	f1->getLW()->normals.push_back(norm);
	if(index_tex!=-1)
		f1->getLW()->texCoords.push_back(tex);
	
	if(l_max==0){
		f2->vert1 = index_cut;	f2->norm1 = index_norm;	f2->tex1 = index_tex;
		f2->vert2 = f1->vert2;	f2->norm2 = f1->norm2;	f2->tex2 = f1->tex2;
		f2->vert3 = f1->vert3;	f2->norm3 = f1->norm3;	f2->tex3 = f1->tex3;

		f1->vert2 = index_cut;
		f1->norm2 = index_norm;
		f1->tex2 = index_tex;
		//std::cout<<"split 1_2: "<<((f1->getLW()->vertices[f1->vert1])-(f1->getLW()->vertices[f1->vert2])).len()<<"-"<<((f2->getLW()->vertices[f1->vert1])-(f2->getLW()->vertices[f1->vert2])).len()<<std::endl;
		
	}
	else
		if(l_max==1){
			f2->vert1 = f1->vert1;	f2->norm1 = f1->norm1;	f2->tex1 = f1->tex1;
			f2->vert2 = f1->vert2;	f2->norm2 = f1->norm2;	f2->tex2 = f1->tex2;
			f2->vert3 = index_cut;	f2->norm3 = index_norm;	f2->tex3 = index_tex;

			f1->vert2 = index_cut;
			f1->norm2 = index_norm;
			f1->tex2 = index_tex;
		
			//std::cout<<"split 2_3: "<<((f1->getLW()->vertices[f1->vert2])-(f1->getLW()->vertices[f1->vert3])).len()<<"-"<<((f2->getLW()->vertices[f1->vert3])-(f2->getLW()->vertices[f1->vert2])).len()<<std::endl;
		}
		else
			if(l_max==2){
				f2->vert1 = index_cut;	f2->norm1 = index_norm;	f2->tex1 = index_tex;
				f2->vert2 = f1->vert2;	f2->norm2 = f1->norm2;	f2->tex2 = f1->tex2;
				f2->vert3 = f1->vert3;	f2->norm3 = f1->norm3;	f2->tex3 = f1->tex3;

				f1->vert3 = index_cut;
				f1->norm3 = index_norm;
				f1->tex3 = index_tex;

				//std::cout<<"split 1_3: "<<((f1->getLW()->vertices[f1->vert1])-(f1->getLW()->vertices[f1->vert3])).len()<<"-"<<((f2->getLW()->vertices[f1->vert1])-(f2->getLW()->vertices[f1->vert3])).len()<<std::endl;
			
			}
	f2->blur = f1->blur;
	f2->material = f1->material;
	//std::cout<<" f1_v1: "<<f1->vert1<<" f1_v2: "<<f1->vert2<<" f1_v3: "<<f1->vert3<<std::endl;
	//std::cout<<" f2_v1: "<<f2->vert1<<" f2_v2: "<<f2->vert2<<" f2_v3: "<<f2->vert3<<std::endl;
	return true;
	};

	
void shiftVertex(LWObject::Face* face){
	//std::cout<<"shiftVertex"<<std::endl;
	//with this intensity the vertexpoint will be shifted
	float intensity = 1.5f;
	//the three vertexpoints of the face
	//std::cout<<"points"<<std::endl;
	Point p1 = face->getLW()->vertices[face->vert1],
		p2 = face->getLW()->vertices[face->vert2],
		p3 = face->getLW()->vertices[face->vert3];
	//the three vertexpoints' normals
	//std::cout<<"normals"<<std::endl;
	Vector norm1 = face->getLW()->normals[face->norm1],
		norm2 = face->getLW()->normals[face->norm2],
		norm3 = face->getLW()->normals[face->norm3];
	//read the shifted-booleans
	//std::cout<<"booleans"<<std::endl;
	bool s1 = face->getLW()->shifted[face->vert1]==1,
		s2 = face->getLW()->shifted[face->vert2]==1,
		s3 = face->getLW()->shifted[face->vert3]==1;
	//the heightmap value for  every vertexppoint
	//std::cout<<"heights"<<std::endl;
	float hmap1 = face->getLW()->materials[face->material].displTexture->sample(face->getLW()->texCoords[face->tex1]).x,
		hmap2 = face->getLW()->materials[face->material].displTexture->sample(face->getLW()->texCoords[face->tex2]).x,
		hmap3 = face->getLW()->materials[face->material].displTexture->sample(face->getLW()->texCoords[face->tex3]).x;
	//shift the vertexpoints and save them again
	//std::cout<<"shift"<<std::endl;
	if(!s1)
		face->getLW()->vertices[face->vert1] = p1 + (intensity*hmap1)*norm1;
	if(!s2)
		face->getLW()->vertices[face->vert2] = p2 + (intensity*hmap2)*norm2;
	if(!s3)
		face->getLW()->vertices[face->vert3] = p3 + (intensity*hmap3)*norm3;
	//no matter if the vertexpoints were shifted now, set shifted to true
	//std::cout<<"set booleans\n"<<std::endl;
	face->getLW()->shifted[face->vert1] = 1;
	face->getLW()->shifted[face->vert2] = 1;
	face->getLW()->shifted[face->vert3] = 1;
}
	
	void readMtlLib(const std::string &_fileName, LWObject::t_materialVector &_matVector, const t_materialMap &_matMap)
	{
		std::ifstream matInput(_fileName.c_str(), std::ios_base::in);
		std::string buf;

		if(matInput.fail())
			throw std::runtime_error("Error opening .mtl file");

		size_t curMtl = -1, curLine = 0;

		while(!matInput.eof())
		{
			std::getline(matInput, buf);
			curLine++;
			const char* cmd = buf.c_str();
			skipWS(cmd);

			if(_strnicmp(cmd, "newmtl", 6) == 0)
			{
				cmd += 6;

				skipWS(cmd);
				std::string name = endSpaceTrimmed(cmd);
				if(_matMap.find(name) == _matMap.end())
					goto parse_err_found;

				curMtl = _matMap.find(name)->second;
			}
			else if(
				_strnicmp(cmd, "Kd", 2) == 0 || _strnicmp(cmd, "Ks", 2) == 0 
				|| _strnicmp(cmd, "Ka", 2) == 0)
			{
				char coeffType = *(cmd + 1);

				if(curMtl == -1)
					goto parse_err_found;

				float4 color;
				color.w = 0;
				cmd += 2;

				char *newCmdString;
				for(int i = 0; i < 3; i++)
				{
					skipWS(cmd);
					((float*)&color)[i] = (float)strtod(cmd, &newCmdString);
					if(newCmdString == cmd) goto parse_err_found;
					cmd = newCmdString; 
				}

				
				switch (coeffType)
				{
					case 'd': 
						_matVector[curMtl].diffuseCoeff = color; break;
					case 'a': 
						_matVector[curMtl].ambientCoeff = color; break;
					case 's': 
						_matVector[curMtl].specularCoeff = color; break;
				}
			}
			else if(_strnicmp(cmd,  "Ns", 2) == 0) 
			{
				if(curMtl == -1)
					goto parse_err_found;

				cmd += 2;

				char *newCmdString;
				skipWS(cmd);
				float coeff = (float)strtod(cmd, &newCmdString);
				if(newCmdString == cmd) goto parse_err_found;
				cmd = newCmdString; 
				_matVector[curMtl].specularExp = coeff;
			}
			else if(
				_strnicmp(cmd,  "map_Kd", 6) == 0 || _strnicmp(cmd,  "map_Ks", 6) == 0
				|| _strnicmp(cmd,  "map_Ka", 6) == 0 || _strnicmp(cmd,  "map_bump", 8) == 0
				|| _strnicmp(cmd,  "map_displ", 9) == 0
				)
			{
				SmartPtr<Texture> &dest = 
					(_strnicmp(cmd, "map_Kd", 6) == 0) ?  _matVector[curMtl].diffuseTexture : 
					((_strnicmp(cmd, "map_Ka", 6) == 0) ? _matVector[curMtl].ambientTexture : 
					((_strnicmp(cmd, "map_Ks", 6) == 0) ? _matVector[curMtl].specularTexture :
					((_strnicmp(cmd,  "map_bump", 8) == 0) ? _matVector[curMtl].bumpTexture :
					_matVector[curMtl].displTexture )));


				bool bumpTex = _strnicmp(cmd,  "map_bump", 8) == 0,
					displTex = _strnicmp(cmd,  "map_displ", 9) == 0;
				cmd += 6;

				if(bumpTex)
				{
					cmd += 2;
					skipWS(cmd);
					if(_strnicmp(cmd, "-bm", 3) == 0)
					{
						cmd += 3;
						char *newCmdString;
						skipWS(cmd);
						float coeff = (float)strtod(cmd, &newCmdString);
						if(newCmdString == cmd) goto parse_err_found;
						cmd = newCmdString; 
						_matVector[curMtl].bumpIntensity = coeff;
					}
				}

				if(displTex){
					cmd += 3;
				}

				skipWS(cmd);
				std::string fn = endSpaceTrimmed(cmd);
				std::string pngFileName = getDirName(_fileName) + _PATH_SEPARATOR + fn;

				SmartPtr<Image> img = new Image;
				img->readPNG(pngFileName);
			
				SmartPtr<Texture> tex = new Texture;
				tex->image = img;

				tex->filterMode = Texture::TFM_Bilinear;

				dest = tex;
			}

			continue;
parse_err_found:
			std::cerr << "Error at line " << curLine << "in " << _fileName <<std::endl;
		}
	}
}

using namespace objLoaderUtil;

void LWObject::read(const std::string &_fileName, bool _createDefautShaders)
{
	std::ifstream inputStream(_fileName.c_str(), std::ios_base::in);
	std::string buf;

	const size_t _MAX_BUF = 8192;
	const size_t _MAX_IDX = _MAX_BUF / 2;

	float tmpVert[4];
	size_t tmpIdx[_MAX_IDX * 3];
	int tmpVertPointer, tmpIdxPtr, vertexType;
	size_t curMat = 0, curLine = 0;
	std::vector<std::string> matFiles;

	char* str="NIX";

	Material defaultMaterial;
	defaultMaterial.name = "Default_{B77D36AF-37CE-4144-B772-E0F00F626DF6}";
	defaultMaterial.diffuseCoeff = float4(1, 1, 1, 0);
	defaultMaterial.specularCoeff = float4(0, 0, 0, 0);
	defaultMaterial.specularExp = 0;
	defaultMaterial.ambientCoeff = float4(0.2f, 0.2f, 0.2f, 0);
	materials.push_back(defaultMaterial);

	materialMap.insert(std::make_pair("defaultMaterial.name", (size_t)0));

	Vector vMotionBlur(0.f,0.f,0.f);

	if(inputStream.fail())
		throw std::runtime_error("Error opening .obj file");

	while(!inputStream.eof())
	{
		std::getline(inputStream, buf);
		const char *cmdString = buf.c_str();

		curLine++;
		skipWS(cmdString);
		switch(tolower(*cmdString))
		{
		case 0:
			break;
		case 'v':
			cmdString++;
			switch(tolower(*cmdString))
			{
				case 'n': vertexType = 1; cmdString++; break;
				case 't': vertexType = 2; cmdString++; break;
				default: 
					if(isspace(*cmdString))
						vertexType = 0;
					else
						goto parse_err_found;
			}

			tmpVertPointer = 0;
			for(;;)
			{
				skipWS(cmdString);
				if(*cmdString == 0)
					break;

				char *newCmdString;
				float flt = (float)strtod(cmdString, &newCmdString);
				if(newCmdString == cmdString)
					goto parse_err_found;

				cmdString = newCmdString;

				if(tmpVertPointer >= sizeof(tmpVert) / sizeof(float))
					goto parse_err_found;

				tmpVert[tmpVertPointer++] = flt;
			}

			if(vertexType != 2 && tmpVertPointer != 3 || vertexType == 2 && tmpVertPointer < 2)
				goto parse_err_found;


			if(vertexType == 0)
				vertices.push_back(*(Point*)tmpVert);
			else if (vertexType == 1)
				normals.push_back(*(Vector*)tmpVert);
			else
				texCoords.push_back(*(float2*)tmpVert);

			break;

		case 'f':
			cmdString++;
			if(tolower(*cmdString) == 'o')
				cmdString++;
			skipWS(cmdString);

			tmpIdxPtr = 0;
			for(;;)
			{
				if(tmpIdxPtr + 3 >= sizeof(tmpIdx) / sizeof(int))
					goto parse_err_found;

				char *newCmdString;
				int idx = strtol(cmdString, &newCmdString, 10);

				if(cmdString == newCmdString)
					goto parse_err_found;

				cmdString = newCmdString;

				tmpIdx[tmpIdxPtr++] = idx - 1;

				skipWS(cmdString);

				if(*cmdString == '/')
				{
					cmdString++;

					skipWS(cmdString);
					if(*cmdString != '/')
					{
						idx = strtol(cmdString, &newCmdString, 10);

						if(cmdString == newCmdString)
							goto parse_err_found;

						cmdString = newCmdString;

						tmpIdx[tmpIdxPtr++] = idx - 1;
					}
					else
						tmpIdx[tmpIdxPtr++] = -1;


					skipWS(cmdString);
					if(*cmdString == '/')
					{
						cmdString++;
						skipWS(cmdString);
						idx = strtol(cmdString, &newCmdString, 10);

						//Do ahead lookup of one number
						skipWS((const char * &)newCmdString);
						if(isdigit(*newCmdString) || (*newCmdString == 0 || *newCmdString == '#') && cmdString != newCmdString)
						{
							if(cmdString == newCmdString)
								goto parse_err_found;

							cmdString = newCmdString;

							tmpIdx[tmpIdxPtr++] = idx - 1;
						}
						else
							tmpIdx[tmpIdxPtr++] = -1;
					}
					else
						tmpIdx[tmpIdxPtr++] = -1;
				}
				else
				{
					tmpIdx[tmpIdxPtr++] = -1;
					tmpIdx[tmpIdxPtr++] = -1;
				}

				skipWS(cmdString);
				if(*cmdString == 0)
					break;
			}

			if(tmpIdxPtr <= 6)
				goto parse_err_found;

			for(int idx = 3; idx < tmpIdxPtr - 3; idx += 3)
			{
				Face t(this);
				t.material = curMat;
				t.blur = vMotionBlur;
				memcpy(&t.vert1, tmpIdx, 3 * sizeof(size_t));
				memcpy(&t.vert2, tmpIdx + idx, 6 * sizeof(size_t));

				faces.push_back(t);
			}
			break;

		case 'o':
		case 'g':
			//read MotionBlur information for each group and store them in vMotionBlur
			cmdString++;
			skipWS(cmdString);
			str = (char*)&*cmdString;
			str += 5;

			if(str[0] =='b'){
				str += 2;
				vMotionBlur.x=(float)strtod(str, &str);
				str++;
				vMotionBlur.y=(float)strtod(str, &str);
				str++;
				vMotionBlur.z=(float)strtod(str, &str);
				//std::cout<<"MotionBlurVector "<<vMotionBlur.x<<" "<<vMotionBlur.y<<" "<<vMotionBlur.z<<std::endl;
			}
			else
				vMotionBlur = Vector(0.f,0.f,0.f);
			break;

		case 's': //?
		case '#':
			//Not supported
			break;

		default:
			if(_strnicmp(cmdString, "usemtl", 6) == 0)
			{
				cmdString += 6;
				skipWS(cmdString);
				std::string name = endSpaceTrimmed(cmdString);
				if(name.empty())
					goto parse_err_found;

				if(materialMap.find(name) == materialMap.end())
				{
					materials.push_back(Material(name));
					materialMap[name] = materials.size() - 1;
				}

				curMat = materialMap[name];
			}
			else if(_strnicmp(cmdString, "mtllib", 6) == 0)
			{
				cmdString += 6;
				skipWS(cmdString);
				std::string name = endSpaceTrimmed(cmdString);
				if(name.empty())
					goto parse_err_found;

				matFiles.push_back(name);
			}
			else
			{
				std::cerr << "Unknown entity at line " << curLine << std::endl;
			}
		}

		continue;
parse_err_found:
		std::cerr << "Error at line " << curLine << std::endl;
	}


	std::string objDir = getDirName(_fileName);

	for(std::vector<std::string>::const_iterator it = matFiles.begin(); it != matFiles.end(); it++)
	{
		std::string mtlFileName = objDir + _PATH_SEPARATOR + *it;

		readMtlLib(mtlFileName, materials, materialMap);
	}

	if(_createDefautShaders)
	{
		for(t_materialVector::iterator it = materials.begin(); it != materials.end(); it++)
		{
			if(it->bumpTexture.data() != NULL)
			{
				/*if(_strnicmp(it->name.c_str(), "Floor", 5) == 0)
				{
					SmartPtr<proceduralShader> shader = new proceduralShader;
					it->shader=shader;
					shader->diffuseCoef = it->diffuseCoeff;
					shader->ambientCoef = it->ambientCoeff;
					shader->specularCoef = it->specularCoeff;
					shader->specularExponent = it->specularExp;
					shader->diffTexture = it->diffuseTexture;
					shader->specTexture = it->specularTexture;
					shader->amibientTexture = it->ambientTexture;
					shader->bumpTexture = it->bumpTexture;
					shader->gapsize =0.04f;
				}
				else*/{
					SmartPtr<bumpPhongShader> shader = new bumpPhongShader;
					it->shader=shader;
					shader->diffuseCoef = it->diffuseCoeff;
					shader->ambientCoef = it->ambientCoeff;
					shader->specularCoef = it->specularCoeff;
					shader->specularExponent = it->specularExp;
					shader->diffTexture = it->diffuseTexture;
					shader->specTexture = it->specularTexture;
					shader->amibientTexture = it->ambientTexture;
					shader->bumpTexture = it->bumpTexture;
				}
			}
			else
			{
				SmartPtr<TexturedPhongShader> shader = new TexturedPhongShader;
				it->shader = shader;
				shader->diffuseCoef = it->diffuseCoeff;
				shader->ambientCoef = it->ambientCoeff;
				shader->specularCoef = it->specularCoeff;
				shader->specularExponent = it->specularExp;
				shader->diffTexture = it->diffuseTexture;
				shader->specTexture = it->specularTexture;
				shader->amibientTexture = it->ambientTexture;
			}
		}

	}

	//initialize the shifted vector
	for(int i=0; i<vertices.size(); i++){
		shifted.push_back(0);
	}

	//int count = 0;
	int size = faces.size();
	std::cout<<"faces before splitting "<<size<<std::endl;
	for(int t=0;t<size;t++)//t_faceVector::iterator it = faces.begin(); it != faces.end(); it++)
	{
		//if(t%5000==0) std::cout<<t<<" von "<<size<<std::endl;
		Face* it = &faces[t];
		if(it->norm1 == -1 || it->norm2 == -1 || it->norm3 == -1)
		{
			Vector e1 = vertices[it->vert2] - vertices[it->vert1];
			Vector e2 = vertices[it->vert3] - vertices[it->vert1];
			Vector n = ~(e1 % e2);
			if(it->norm1 == -1) it->norm1 = normals.size();
			if(it->norm2 == -1) it->norm2 = normals.size();
			if(it->norm3 == -1) it->norm3 = normals.size();

			normals.push_back(n);
		}
		//split faces from objects with displacement mapping
		if(it->getLW()->materials[it->material].displTexture.data() != NULL){
			
			Face f2(this);
			//stack with the faces, which have to get splitted
			std::stack<Face> splitStack;

			//split the first face
			bool ret = split(it->getMyself(), &f2);
			//if splitting was successful, put both new faces on the stack, initialize f2 again
			if(ret){
				splitStack.push(*it->getMyself());
				splitStack.push(f2);
				f2 = Face(this);
			}
			//whileloop until stack is empty; if first split wasn't successful, skip the whileloop
			while(!splitStack.empty()){
				//split the next one from the stack
				ret = split(&splitStack.top(), &f2);
				//if splitting was successful, put f2 on the stack and continue with the new one
				if(ret){
					splitStack.push(f2);
					f2 = Face(this);
				}
				//if splitting wasn't successful, remove this small face from the stack
				else{
					//if this is the last face, which can't get splitted, overwrite the "it" face in faces
					if(splitStack.size()==1)
						faces[t] = splitStack.top();
					//if there are more faces to split, push it in faces
					else{
						faces.push_back(splitStack.top());
					}

					splitStack.pop();
				}
			}
		}
	}
	std::cout<<"faces after splitting "<<faces.size()<<std::endl;
	for(int f=0;f<faces.size();f++){
		if(materials[faces[f].material].displTexture.data() != NULL){
			shiftVertex(&faces[f]);
		}
	}
}

